package com.pq.pqojcodesandbox.utils;

import cn.hutool.core.util.StrUtil;
import com.pq.pqojcodesandbox.model.ExecuteMessage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.StopWatch;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 进程工具类
 */
public class ProcessUtils {

    /**
     * 执行进程并获取信息
     *
     *执行一个已经启动的操作系统进程（Process 对象），并获取该进程的执行结果，包括：
     *
     * 是否正常退出（通过 exitValue 判断）
     * 正常输出（stdout）
     * 错误输出（stderr）
     * 执行耗时
     *
     * @param runProcess
     * @param opName
     * @return
     */
    public static ExecuteMessage runProcessAndGetMessage(Process runProcess, String opName) {
        ExecuteMessage executeMessage = new ExecuteMessage();
        try {
            //  启动计时器(初始化计时器)
            StopWatch stopWatch = new StopWatch();

            stopWatch.start();
            //  等待程序执行，获取退出码
            int exitValue = runProcess.waitFor();
            executeMessage.setExitValue(exitValue);
            // 等待编译进程完成，获取退出值，正常退出 （0表示成功，非0表示失败。）
            if (exitValue == 0) {
                System.out.println(opName + "编译成功");
                // 分批获取进程的正常输出
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(runProcess.getInputStream()));
                List<String> outputStrList = new ArrayList<>();
                // 逐行读取，用于存储输出内容
                String compileOutputLine;
                //  用于存储每行输出
                while ((compileOutputLine = bufferedReader.readLine()) != null) {
                    outputStrList.add(compileOutputLine);
                }
                //  将多行输出拼接程一个字符串，在存入(用换行符拼接输出内容，存入ExecuteMessage)
                executeMessage.setMessage(StringUtils.join(outputStrList, "\n"));
            } else {
                // 异常退出（处理失败，也就是不等于0）
                System.out.println(opName + "编译失败，错误码： " + exitValue);
                // 读取标准(分批获取进程的正常输出)
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(runProcess.getInputStream()));
                List<String> outputStrList = new ArrayList<>();
                // 逐行读取，用于存储输出内容
                String compileOutputLine;
                //  用于存储每行输出
                while ((compileOutputLine = bufferedReader.readLine()) != null) {
                    outputStrList.add(compileOutputLine);
                }
                executeMessage.setMessage(StringUtils.join(outputStrList, "\n"));


                // 分批获取进程的错误输出
                BufferedReader errorBufferedReader = new BufferedReader(new InputStreamReader(runProcess.getErrorStream()));

                // 逐行读取，用于存储输出内容 未成功一样输出
                List<String> errorOutputStrList = new ArrayList<>();
                // 逐行读取，用于存储输出内容
                String errorCompileOutputLine;
                //  用于存储每行输出
                while ((errorCompileOutputLine = errorBufferedReader.readLine()) != null) {
                    errorOutputStrList.add(errorCompileOutputLine);
                }
                executeMessage.setErrorMessage(StringUtils.join(errorCompileOutputLine, "\n"));
            }
            //  停止计时
            stopWatch.stop();
            //  计算进程执行时间(毫秒)
            executeMessage.setTime(stopWatch.getLastTaskTimeMillis());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return executeMessage;

    }

    /**
     * 执行交互式进程并获取信息（如命令行输入程序），向进程发送输入参数并捕获输出。gt
     *
     * @param runProcess
     * @param args
     * @return
     */
    public static ExecuteMessage runInteractProcessAndGetMessage(Process runProcess, String args) {
        ExecuteMessage executeMessage = new ExecuteMessage();
        try {
            //  向控制台输入程序
            OutputStream outputStream = runProcess.getOutputStream();
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
            //  将输入参数按空格拆分，用换行符拼接(模拟逐行输入)
            String[] s = args.split(" ");
            String join = StrUtil.join("\n", s) + "\n";
            outputStreamWriter.write(join);
            //  相当于按了回车，执行输入的发送
            outputStreamWriter.flush();

            // 分批获取进程的正常输出(逐行读取进程的标准输出，拼接成完整字符串。)
            InputStream inputStream = runProcess.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            //  创建缓冲读取器，读取进程的标准输出流
            StringBuilder compileOutputStringBuilder = new StringBuilder();
            // 逐行读取，用于存储输出内容
            String compileOutputLine;
            //  用于存储每行输出
            while ((compileOutputLine = bufferedReader.readLine()) != null) {
                compileOutputStringBuilder.append(compileOutputLine);
            }
            executeMessage.setMessage(compileOutputStringBuilder.toString());
            //  资源的释放，回收，避免出现卡死(关闭所有流并销毁进程，避免资源泄漏或进程僵死)
            outputStreamWriter.close();
            outputStream.close();
            inputStream.close();
            runProcess.destroy();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return executeMessage;

    }

}